package alp.starcode.framework.netty;


import alp.starcode.framework.enums.MsgActionEnum;
import alp.starcode.framework.model.ChatMsg;
import alp.starcode.framework.model.DataContent;
import alp.starcode.framework.utils.JsonUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;

/**
 * 处理 web socket 文本消息
 *
 * @author yang
 * @date 2018/11/7 - 17:37
 */
@Component
public class TextWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private static final Logger log = LoggerFactory.getLogger(TextWebSocketHandler.class);

    // 用于记录和管理所有客户端的channle
    public static ChannelGroup users =
            new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws UnsupportedEncodingException {
        log.info("接收到客户端的消息:[{}]", msg.text());

        Channel currentChanner = ctx.channel();
        // 1. 获取客户端发来的消息

        DataContent dataContent = JsonUtils.jsonToPojo(msg.text(), DataContent.class);
        Integer action = dataContent.getAction();
        // 2. 判断消息类型，根据不同的类型来处理不同的业务
        // 	2.1  当websocket 第一次open的时候，初始化channel，把用的channel和userid关联起来
        if (action == MsgActionEnum.CONNECT.getType()) {
            // 	2.1  当websocket 第一次open的时候，初始化channel，把用的channel和userid关联起来
            String senderUserId = dataContent.getChatMsg().getSenderId();
            UserChannelRel.put(senderUserId, currentChanner);
            log.info("连接成功");
            for (Channel c :
                    users) {
                System.out.println(c.id().asLongText());
            }
            UserChannelRel.output();
        } else if (action == MsgActionEnum.CHAT.getType()) {
            ChatMsg chatMsg = dataContent.getChatMsg();
            /*if (chatMsg.getType()==1){
                String msgText = chatMsg.getMsg();
            }*/
            String msgText = chatMsg.getMsg();
            byte[] textByte = msgText.getBytes("UTF-8");
            Base64 base64 = new Base64();
            String newEncode = base64.encodeToString(textByte);
            chatMsg.setMsg(newEncode);
            String receiverId = chatMsg.getReceiverId();
            String serderId = chatMsg.getSenderId();
            //保存消息到数据库,标记为未签收
            String enComment = new String(base64.decode(chatMsg.getMsg()), "UTF-8");
            chatMsg.setMsg(enComment);
            DataContent dataContentMsg = new DataContent();

            dataContentMsg.setChatMsg(chatMsg);
            dataContentMsg.setAction(action);

            //发送消息
            Channel receiverChannel = UserChannelRel.get(receiverId);
            if (receiverChannel == null) {
                return;
                // TODO channel为空代表用户离线，推送消息（JPush，个推，小米推送）
            } else {
                // 当receiverChannel不为空的时候，从ChannelGroup去查找对应的channel是否存在
                Channel findChannel = users.find(receiverChannel.id());
                if (findChannel != null) {
                    /* receiverChannel.writeAndFlush(new TextWebSocketFrame(JsonUtils.objectToJson(chatMsg)));*/
                    String str = chatMsg.getSenderId() + "发送给" + chatMsg.getReceiverId() + "的消息，消息内容是:" + chatMsg.getMsg();
                    // 用户在线
                    receiverChannel.writeAndFlush(
                            new TextWebSocketFrame(
                                    JsonUtils.objectToJson(chatMsg)));

                } else {
                    // 用户离线 TODO 推送消息
                }
            }

        } else if (action == MsgActionEnum.SIGNED.getType()) {
//            ChatService chatService= (ChatService) SpringUtil.getBean("chatServiceImpl");
//            String msgId=dataContent.getExtand();
//            String msgTexts[]=msgId.split(",");
//
//            List<String> msgIdList = new ArrayList<>();
//            for (String mid : msgTexts) {
//                if (StringUtils.isNotBlank(mid)) {
//                    msgIdList.add(mid);
//                }
//            }
//            System.out.println(msgIdList.toString());
//
//            if (msgIdList != null && !msgIdList.isEmpty() && msgIdList.size() > 0) {
//                // 批量签收
//                chatService.updateStatus(msgIdList);
//            }
        } else if (action == MsgActionEnum.KEEPALIVE.getType()) {

        }
        //  2.2  聊天类型的消息，把聊天记录保存到数据库，同时标记消息的签收状态[未签收]
        // 保存消息到数据库，并且标记为 未签收
        // 发送消息
        // TODO 从全局用户Channel关系中获取接受方的channel
        // TODO channel为空代表用户离线，推送消息（JPush，个推，小米推送）
        // 当receiverChannel不为空的时候，从ChannelGroup去查找对应的channel是否存在
        // 用户离线 TODO 推送消息
        // 如果是向客户端发送文本消息，则需要发送 TextWebSocketFrame 消息
//        InetSocketAddress inetSocketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
//        String ip = inetSocketAddress.getHostName();
//        String txtMsg = "[" + ip + "][" + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")) + "] ==> " + msg.text();
//        users.writeAndFlush(new TextWebSocketFrame(txtMsg));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
        log.error("服务器发生了异常:", cause);
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        users.add(ctx.channel());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        users.remove(ctx.channel());
    }


    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
            log.info("web socket 握手成功。");
            WebSocketServerProtocolHandler.HandshakeComplete handshakeComplete = (WebSocketServerProtocolHandler.HandshakeComplete) evt;
            String requestUri = handshakeComplete.requestUri();
            log.info("requestUri:[{}]", requestUri);
            String subproTocol = handshakeComplete.selectedSubprotocol();
            log.info("subproTocol:[{}]", subproTocol);
            handshakeComplete.requestHeaders().forEach(entry -> log.info("header key:[{}] value:[{}]", entry.getKey(), entry.getValue()));
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
    }

    public void sendMessage(String receiverId, String msg) {
        //发送消息
        Channel receiverChannel = UserChannelRel.get(receiverId);
        if (receiverChannel == null) {
            return;
            // TODO channel为空代表用户离线，推送消息（JPush，个推，小米推送）
        } else {
            // 当receiverChannel不为空的时候，从ChannelGroup去查找对应的channel是否存在
            Channel findChannel = users.find(receiverChannel.id());
            if (findChannel != null) {
                /* receiverChannel.writeAndFlush(new TextWebSocketFrame(JsonUtils.objectToJson(chatMsg)));*/
                // String str = chatMsg.getSenderId()+"发送给"+chatMsg.getReceiverId()+"的消息，消息内容是:"+chatMsg.getMsg();
                // 用户在线
                receiverChannel.writeAndFlush(
                        new TextWebSocketFrame(
                                msg));
            } else {
                // 用户离线 TODO 推送消息
            }
        }
    }

    public void broadcast(String msg) {
        if (users.size() > 0) {
            for (Channel c:
                    users) {
                //System.out.println(c.id().asLongText());
                c.writeAndFlush(new TextWebSocketFrame(msg));
            }
        }
    }
}